NIO 教程

1. 概述

1.1 什么是 NIO?

NIO(New I/O)是 Java 1.4 引入的一组新的 I/O API,旨在提高 I/O 操作的效率和性能。NIO 提供了非阻塞 I/O 操作、缓冲区管理和通道等新特性,使得处理大量数据和高并发场景变得更加高效。

1.2 NIO 的核心组件

  • Buffer(缓冲区):用于存储数据。
  • Channel(通道):用于读写数据。
  • Selector(选择器):用于管理多个通道的非阻塞 I/O 操作。

2. Buffer(缓冲区)

2.1 缓冲区的基本概念

缓冲区是 NIO 中用于存储数据的容器。每个缓冲区都有以下几个重要的属性:

  • Capacity(容量):缓冲区可以存储的最大数据量。
  • Position(位置):当前读写的位置。
  • Limit(限制):当前缓冲区的有效数据量。

2.2 缓冲区的创建和使用

import java.nio.ByteBuffer;

public class BufferExample {
    public static void main(String[] args) {
        // 创建一个容量为10的ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(10);

        // 写入数据
        buffer.put((byte) 10);
        buffer.put((byte) 20);

        // 切换到读模式
        buffer.flip();

        // 读取数据
        while (buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }

        // 清空缓冲区
        buffer.clear();
    }
}

3. Channel(通道)

3.1 通道的基本概念

通道是 NIO 中用于读写数据的管道。通道可以分为两类:

  • FileChannel:用于文件 I/O。
  • SocketChannel 和 ServerSocketChannel:用于网络 I/O。

3.2 文件通道的使用

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

public class FileChannelExample {
    public static void main(String[] args) throws Exception {
        FileInputStream input = new FileInputStream("input.txt");
        FileOutputStream output = new FileOutputStream("output.txt");

        FileChannel inputChannel = input.getChannel();
        FileChannel outputChannel = output.getChannel();

        // 从输入通道读取数据并写入输出通道
        inputChannel.transferTo(0, inputChannel.size(), outputChannel);

        input.close();
        output.close();
    }
}

4. Selector(选择器)

4.1 选择器的基本概念

选择器用于管理多个通道的非阻塞 I/O 操作。通过选择器,可以同时监听多个通道的事件,如连接、读取和写入。

4.2 选择器的使用

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class SelectorExample {
    public static void main(String[] args) throws Exception {
        Selector selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.socket().bind(new InetSocketAddress(8080));
        serverChannel.configureBlocking(false);
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();

                if (key.isAcceptable()) {
                    SocketChannel clientChannel = serverChannel.accept();
                    clientChannel.configureBlocking(false);
                    clientChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel clientChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    clientChannel.read(buffer);
                    buffer.flip();
                    System.out.println("Received: " + new String(buffer.array()));
                }
            }
        }
    }
}

5. 实践练习

5.1 练习1:文件复制

编写一个程序,使用 FileChannel 实现文件的复制功能。

5.2 练习2:简单的聊天服务器

编写一个简单的聊天服务器,使用 Selector 和 SocketChannel 实现多客户端的连接和消息传递。

6. 总结

NIO 提供了高效的 I/O 操作方式,特别适用于高并发和大数据量的场景。通过学习 Buffer、Channel 和 Selector,你可以更好地理解和应用 NIO 技术,提升程序的性能和效率。

7. 参考资料

通过本教程的学习,你应该能够掌握 NIO 的基本概念和使用方法,并能够在实际项目中应用这些知识。